﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using MacomberMapSystem.Common.Serialization;
using MacomberMapSystem.Common.Database;
using MacomberMapSystem.Common.Integration;
using System.Runtime.InteropServices;
using System.Threading;

namespace MacomberMapSystem.Common.User_Interfaces.Mapping
{
    /// <summary>
    /// This class provides our GIS data linkage form
    /// </summary>
    public partial class frmGISData : DockContent
    {
        #region Variable declarations
        /// <summary>Our repository</summary>
        private static MM_Repository Repository;

        /// <summary>Our collection of GIS stations</summary>
        private List<GIS_Substation_Edit> GIS_Substations = new List<GIS_Substation_Edit>();

        /// <summary>Our collection of GIS lines</summary>
        private List<GIS_Line_Edit> GIS_Lines = new List<GIS_Line_Edit>();

        /// <summary>Our collection of MM stations</summary>
        private List<MM_Substation_Edit> MM_Substations = new List<MM_Substation_Edit>();
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize a new GIS data form
        /// </summary>
        /// <param name="Repository"></param>
        public frmGISData(MM_Repository Repository)
        {
            InitializeComponent(); 
            frmGISData.Repository = Repository;
            foreach (GIS_Substation Sub in Repository.Db.GISSubstations.Values)
                GIS_Substations.Add(new GIS_Substation_Edit(Sub));
            foreach (MM_Substation Sub in Repository.Db.Substations.Values)
                MM_Substations.Add(new MM_Substation_Edit(Sub));
            GIS_Substations.Sort();
            MM_Substations.Sort();
            dgvGISSubstations.DataSource = GIS_Substations.ToArray();
            dgvERCOTSubstations.DataSource = MM_Substations.ToArray();
        }
        #endregion


        #region Editor classes
        /// <summary>This class provides our editor for our GIS substation</summary>
        private class GIS_Substation_Edit: IComparable<GIS_Substation_Edit>
        {
            /// <summary>Our linked substation</summary>
            public GIS_Substation Sub;

            /// <summary>Report hte name of our substation</summary>
            public String Name { get { return Sub.Name; } }

            /// <summary>Report the company of our substation</summary>
            public String Company { get { return Sub.Company; } }

            /// <summary>Report the TEID of our substation</summary>
            public UInt64 TEID
            {
                get { return Sub.TEID; }
                set { Sub.TEID = value; Sub.ValidatedBy = Repository.CurrentUser; Sub.ValidatedOn = DateTime.Now; }
            }

            /// <summary>
            /// Initialize a new substation
            /// </summary>
            /// <param name="Sub"></param>
            public GIS_Substation_Edit(GIS_Substation Sub)
            {
                this.Sub = Sub;
            }

            /// <summary>
            /// Compare two substations
            /// </summary>
            /// <param name="other"></param>
            /// <returns></returns>
            public int CompareTo(GIS_Substation_Edit other)
            {
                int Comp = Name.CompareTo(other.Name);
                return Comp != 0 ? Comp : Sub.Sub_Id.CompareTo(other.Sub.Sub_Id);
            }
        }

        /// <summary>This class provides our editor for our GIS substation</summary>
        private class GIS_Line_Edit : IComparable<GIS_Line_Edit>
        {
            /// <summary>Our linked substation</summary>
            public GIS_Line Line;

            /// <summary>Report hte name of our substation</summary>
            public String Name { get { return Line.Name; } }

            /// <summary>Report the company of our substation</summary>
            public String Company { get { return Line.Company; } }

            /// <summary>Report the TEID of our substation</summary>
            public UInt64 TEID
            {
                get { return Line.TEID; }
                set { Line.TEID = value; Line.ValidatedBy = Repository.CurrentUser; Line.ValidatedOn = DateTime.Now; }
            }

            /// <summary>
            /// Initialize a new substation
            /// </summary>
            /// <param name="Sub"></param>
            public GIS_Line_Edit(GIS_Line Line)
            {
                this.Line = Line;
            }

            /// <summary>
            /// Compare two substations
            /// </summary>
            /// <param name="other"></param>
            /// <returns></returns>
            public int CompareTo(GIS_Line_Edit other)
            {
                int Comp = Name.CompareTo(other.Name);
                return Comp != 0 ? Comp : Line.Line_Id.CompareTo(other.Line.Line_Id);
            }
        }


        /// <summary>This class provides our editor for our MM substation</summary>
        private class MM_Substation_Edit: IComparable<MM_Substation_Edit>
        {
            /// <summary>Our linked substation</summary>
            public MM_Substation Sub;

            /// <summary>Our substation name</summary>
            public String Name { get { return Sub.Name; } }

            /// <summary>Our long name</summary>
            public String LongName
            {
                get
                {
                    if (String.IsNullOrEmpty(Sub.LongName))
                        return Sub.Name;
                    else
                        return Sub.LongName;
                }
            }

            /// <summary>Our GIS ID</summary>
            public UInt64 GIS_Id { get; set; }

            /// <summary>
            /// Initialize a new MM substation
            /// </summary>
            /// <param name="Sub"></param>
            public MM_Substation_Edit(MM_Substation Sub)
            {
                this.Sub = Sub;
            }

            public int CompareTo(MM_Substation_Edit other)
            {
                int Comp = LongName.CompareTo(other.LongName);
                return Comp != 0 ? Comp : Sub.TEID.CompareTo(other.Sub.TEID);
            }
        }
    #endregion

        #region Shapefile loading
        /// <summary>
        /// Load in our collection of substations
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLoadSubstations_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog oFd = new OpenFileDialog() { Title = "Load GIS substations", Filter = "GIS Shapefile (*.shp)|*.shp" })
                if (oFd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    ThreadPool.QueueUserWorkItem(new WaitCallback(LoadSubstationsInSeparateThread), oFd.FileName);
        }

        /// <summary>
        /// Load our substations in a different thread
        /// </summary>
        /// <param name="state"></param>
        private void LoadSubstationsInSeparateThread(object state)
        {
            using (ShapeFile InShape = ShapeFile.Open((string)state))
            {
                Dictionary<String, KeyValuePair<int, AttributeTypes>> Cols = new Dictionary<string, KeyValuePair<int, AttributeTypes>>();

                for (int a = 0; a < InShape.Attributes.Length; a++)
                    Cols.Add(InShape.Attributes[a].Name, new KeyValuePair<int, AttributeTypes>(a, InShape.Attributes[a].Type));

                GIS_Substations.Clear();
                //Now, read through each shape
                foreach (Shape ShapeToRead in InShape)
                {
                    PointD LatLong = new PointD(ShapeToRead.Vertices[0].X, ShapeToRead.Vertices[0].Y);
                    if (Repository.Db.StateBoundary.HitTest(LatLong))
                    {
                        String SubName = (string)ShapeToRead.GetAttribute(Cols["SUB_NAME"].Key);
                        String CompanyName = (string)ShapeToRead.GetAttribute(Cols["COMP_NAME"].Key);

                        double SubId = (Double)ShapeToRead.GetAttribute(Cols["SUB_ID"].Key);
                        if (SubId == -99)
                            SubId = (double)ShapeToRead.GetAttribute(Cols["COMP_ID"].Key);
                        GIS_Substations.Add(new GIS_Substation_Edit(new GIS_Substation() { Company = CompanyName, Name = SubName, Sub_Id = (UInt64)SubId, Latitude = LatLong.Y, Longitude = LatLong.X }));
                        if ((GIS_Substations.Count % 100) == 0)
                            Console.WriteLine("Loaded {0:#,##0} substations", GIS_Substations.Count);
                    }
                }
                dgvERCOTSubstations.Invoke(new SafeCompleteSubstations(CompleteSubstations));
            }
        }

        private delegate void SafeCompleteSubstations();
        
        /// <summary>
        /// Complete our list of substations
        /// </summary>
        private void CompleteSubstations()
        {
                dgvGISSubstations.Invalidate();
                dgvGISSubstations.DataSource = GIS_Substations.ToArray();
                MessageBox.Show("Loaded " + GIS_Substations.Count.ToString("#,##0") + " substations.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);            
        }

        /// <summary>
        /// Load in our collection of lines
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLoadLineShapefiles_Click(object sender, EventArgs e)
        {

            using (OpenFileDialog oFd = new OpenFileDialog() { Title = "Load GIS lines", Filter = "GIS Shapefile (*.shp)|*.shp" })
                if (oFd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    ThreadPool.QueueUserWorkItem(new WaitCallback(LoadLinesInSeparateThread), oFd.FileName);
   
        }


        /// <summary>
        /// Load our substations in a different thread
        /// </summary>
        /// <param name="state"></param>
        private void LoadLinesInSeparateThread(object state)
        {
            using (ShapeFile InShape = ShapeFile.Open((string)state))
            {
                Dictionary<String, KeyValuePair<int, AttributeTypes>> Cols = new Dictionary<string, KeyValuePair<int, AttributeTypes>>();

                for (int a = 0; a < InShape.Attributes.Length; a++)
                    Cols.Add(InShape.Attributes[a].Name, new KeyValuePair<int, AttributeTypes>(a, InShape.Attributes[a].Type));

                GIS_Lines.Clear();
                //Now, read through each shape
                foreach (Shape ShapeToRead in InShape)
                {
                    /* PointD LatLong = new PointD(ShapeToRead.Vertices[0].X, ShapeToRead.Vertices[0].Y);
                     if (Repository.Db.StateBoundary.HitTest(LatLong))
                     {
                         String SubName = (string)ShapeToRead.GetAttribute(Cols["SUB_NAME"].Key);
                         String CompanyName = (string)ShapeToRead.GetAttribute(Cols["COMP_NAME"].Key);

                         double SubId = (Double)ShapeToRead.GetAttribute(Cols["SUB_ID"].Key);
                         if (SubId == -99)
                             SubId = (double)ShapeToRead.GetAttribute(Cols["COMP_ID"].Key);
                         GIS_Substations.Add(new GIS_Substation_Edit(new GIS_Substation() { Company = CompanyName, Name = SubName, Sub_Id = (UInt64)SubId, Latitude = LatLong.Y, Longitude = LatLong.X }));
                         if ((GIS_Substations.Count % 100) == 0)
                             Console.WriteLine("Loaded {0:#,##0} substations", GIS_Substations.Count);
                     }*/
                }
                dgvERCOTSubstations.Invoke(new SafeCompleteSubstations(CompleteLines));
            }
        }

        /// <summary>
        /// Complete our collection of lines
        /// </summary>
        private void CompleteLines()
        {
        }
        #endregion

        private void UpdateElementData(object sender, EventArgs e)
        {

        }

    }
}
